// SSLTest.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
//#include <openssl/ssl.h>

//#using <mscorlib.dll>
#include <windows.h>
#include <wincrypt.h>
#include <schannel.h>
#define SECURITY_WIN32
#include <security.h>
#include <sspi.h>
#include "tchar.h"
#include <assert.h>

#include <exception>
#include <string>
#include <vector>

//using namespace System;
//using namespace System::Net;
//using namespace System::Runtime::InteropServices;
//
#pragma comment(lib, "Crypt32")
#pragma comment(lib, "Secur32")
#pragma comment(lib, "WSock32")

class Buffers : public SecBufferDesc
{
	protected:
	SecBuffer* bufs;
	int nb;
	SecurityFunctionTable* sf;

	public:
	Buffers(int nBufs)
	{
		nb = nBufs;
		bufs = new SecBuffer[nBufs];
		cBuffers = nb;
		pBuffers = bufs;
		ulVersion = SECBUFFER_VERSION;
	}

	~Buffers() { delete[] bufs; }

	void SetBuffer(int i, unsigned long buftype, void* buf, int size)
	{
		bufs[i].BufferType = buftype;
		bufs[i].cbBuffer = size;
		bufs[i].pvBuffer = buf;
	}

	void SetBufferToken(int i, void* buf, int size) { SetBuffer(i, SECBUFFER_TOKEN, buf, size); }
	void SetBufferStreamHeader(int i, void* buf, int size) { SetBuffer(i, SECBUFFER_STREAM_HEADER, buf, size); }
	void SetBufferStreamTrailer(int i, void* buf, int size) { SetBuffer(i, SECBUFFER_STREAM_TRAILER, buf, size); }
	void SetBufferData(int i, void* buf, int size) { SetBuffer(i, SECBUFFER_DATA, buf, size); }
	void SetBufferEmpty(int i) { SetBuffer(i, SECBUFFER_EMPTY, NULL, 0); }

	int totalLength() { int length = 0; for (int i = 0; i < nb; i++) length += bufs[i].cbBuffer; return length; }

	SecBuffer& operator[](int i) { assert(i < nb); return bufs[i]; }
};

class AutoBuffers : public Buffers
{
	SecurityFunctionTable* sf;

	public:
	AutoBuffers(int nBufs, SecurityFunctionTable* pSecurityFunc): Buffers(nBufs)
	{
		sf = pSecurityFunc;
	}

	~AutoBuffers()
	{
		for (int i=0; i<nb; i++)
			sf->FreeContextBuffer(bufs[i].pvBuffer);
	}
};

class ssl_exception: public std::runtime_error
{
	public:
		ssl_exception(const std::string& whatsup): std::runtime_error(whatsup) {}
};

std::string vformat(const char* fmt, va_list ap)
{
	const int INIT_BUF_SIZE = 100;

	int n, size = INIT_BUF_SIZE;
	char *p, *np;

	if ((p = (char*)malloc (size)) == NULL)
		throw new std::bad_alloc();

	while (1)
	{
		va_list ap;
		va_start(ap, fmt);
		n = vsnprintf (p, size, fmt, ap);
		va_end(ap);
		if (n > -1 && n < size)
			return std::string(p);
		if (n > -1)
			size = n+1;
		else
			size *= 2;
		if ((np = (char*)realloc (p, size)) == NULL)
		{
			free(p);
			throw new std::bad_alloc();
		}
		else
			p = np;
	}
}

std::string format(const char* fmt, ...)
{
	va_list ap;
	va_start(ap, fmt);
	std::string buf = vformat(fmt, ap);
	va_end(ap);
	return buf;
}

//
//static void processError(SSL* ssl, int ret)
//{
//	int err = SSL_get_error(ssl, ret);
//	switch (err)
//	{
//		case SSL_ERROR_ZERO_RETURN:
//			printf("The TLS/SSL connection has been closed. If the protocol version is SSL 3.0 or TLS 1.0, this result code is returned only if a closure alert has occurred in the protocol, i.e. if the connection has been closed cleanly. Note that in this case SSL_ERROR_ZERO_RETURN does not necessarily indicate that the underlying transport has been closed.");
//			break;
//		case SSL_ERROR_WANT_READ:
//		case SSL_ERROR_WANT_WRITE:
//			printf("The operation did not complete; the same TLS/SSL I/O function should be called again later. If, by then, the underlying BIO has data available for reading (if the result code is SSL_ERROR_WANT_READ) or allows writing data (SSL_ERROR_WANT_WRITE), then some TLS/SSL protocol progress will take place, i.e. at least part of an TLS/SSL record will be read or written. Note that the retry may again lead to a SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE condition. There is no fixed upper limit for the number of iterations that may be necessary until progress becomes visible at application protocol level.");
//			break;
//		case SSL_ERROR_WANT_CONNECT:
//		case SSL_ERROR_WANT_ACCEPT:
//			printf("The operation did not complete; the same TLS/SSL I/O function should be called again later. The underlying BIO was not connected yet to the peer and the call would block in connect()/accept(). The SSL function should be called again when the connection is established. These messages can only appear with a BIO_s_connect() or BIO_s_accept() BIO, respectively. In order to find out, when the connection has been successfully established, on many platforms select() or poll() for writing on the socket file descriptor can be used.");
//			break;
//		case SSL_ERROR_WANT_X509_LOOKUP:
//			printf("The operation did not complete because an application callback set by SSL_CTX_set_client_cert_cb() has asked to be called again. The TLS/SSL I/O function should be called again later. Details depend on the application.");
//			break;
//		case SSL_ERROR_SYSCALL:
//			printf("Some I/O error occurred. The OpenSSL error queue may contain more information on the error. If the error queue is empty (i.e. ERR_get_error() returns 0), ret can be used to find out more about the error: If ret == 0, an EOF was observed that violates the protocol. If ret == -1, the underlying BIO reported an I/O error (for socket I/O on Unix systems, consult errno for details).");
//			break;
//		case SSL_ERROR_SSL:
//			printf("Generic SSL error");
//			break;
//	}
//}

//#include <windows.h>
//#include <stdio.h>
//#pragma comment(lib, "crypt32.lib")

#define MACHINE_NAME "localhost"

PCCERT_CONTEXT getServerCertificate ()
{
	HCERTSTORE hMyCertStore = NULL;
	PCCERT_CONTEXT aCertContext = NULL;

	hMyCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM,
		X509_ASN_ENCODING,
		0,
		CERT_SYSTEM_STORE_LOCAL_MACHINE,
		L"MY");

	if (hMyCertStore == NULL) 
		printf("Error opening MY store for server.\n");
	else
	{
		aCertContext = CertFindCertificateInStore(hMyCertStore, 
			X509_ASN_ENCODING, 
			0,
			CERT_FIND_SUBJECT_STR_A,
			MACHINE_NAME, // use appropriate subject name
			NULL
			);

		if (aCertContext == NULL)
			printf("Error retrieving server certificate.");
	}
	if(hMyCertStore)
		CertCloseStore(hMyCertStore,0);
	return aCertContext;
}

int _tmain(int argc, _TCHAR* argv[])
{
	WSADATA wsaData;
	const int WSA_VERSION_REQUESTED = MAKEWORD(2,2);
	int returncode = WSAStartup(WSA_VERSION_REQUESTED, &wsaData);
	if (returncode != 0)
		printf("Error %d returned by WSAStartup\n", returncode); 
	printf("----- WinSock Initialized\n");

    SOCKET s = socket(AF_INET, SOCK_STREAM, 0); // IPv4, TCP, no protocol
    if(s == INVALID_SOCKET)
        printf("Error %d creating socket\n", WSAGetLastError());

	const char* SERVER_NAME = "minimac.aprelev.com";
    struct hostent *hp;
	if((hp = gethostbyname(SERVER_NAME)) == NULL)
		printf("Error %d returned by gethostbyname\n", WSAGetLastError());
 
	const int PORT_NUMBER = 993;

    struct sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons((u_short)PORT_NUMBER);
	memcpy(&sin.sin_addr, hp->h_addr, 4);

	returncode = connect(s, (struct sockaddr*)&sin, sizeof(sin));
	if (returncode != 0)
    {
        printf( "Error %d connecting to \"%s\" (%s)\n",  WSAGetLastError(), SERVER_NAME,  inet_ntoa(sin.sin_addr));
        closesocket(s);
    }

	HMODULE hSecurity = LoadLibrary(L"Security.dll");
    INIT_SECURITY_INTERFACE pInitSecurityInterface =
		(INIT_SECURITY_INTERFACE)GetProcAddress(hSecurity, "InitSecurityInterfaceW");
	SecurityFunctionTable* pSecurityFunc = pInitSecurityInterface();
	if (pSecurityFunc == NULL)
		printf("Failed to initialized security interface: %d\n", GetLastError());


	unsigned long nPackages;
	PSecPkgInfo pPackages;
	returncode = pSecurityFunc->EnumerateSecurityPackagesW(&nPackages, &pPackages);
	if (FAILED(returncode))
		throw new ssl_exception(format("Failed to EnumerateSecurityPackages: 0x%x\n", GetLastError()));
	
	for(unsigned long i=0; i<nPackages; i++)
		wprintf(L"Package %d: %s, %s\n", i, pPackages[i].Name, pPackages[i].Comment);

	FreeContextBuffer(pPackages);

	SCHANNEL_CRED SchannelCred;

	ZeroMemory( &SchannelCred, sizeof(SchannelCred) );
	SchannelCred.dwVersion  = SCHANNEL_CRED_VERSION;
	SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1;
	SchannelCred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS | SCH_CRED_MANUAL_CRED_VALIDATION;

	CredHandle hClientCredentials;
	TimeStamp tsExpiry;

	returncode = pSecurityFunc->AcquireCredentialsHandle(
		NULL, // principal name
		UNISP_NAME_W, // package name
		SECPKG_CRED_OUTBOUND, // use - prepare an outgoing token
		NULL, // logon id pointer
		&SchannelCred, // package specific data
		NULL, // GetKey() fun pointer
		NULL, // GetKey() parameter
		&hClientCredentials, // out - credential handle
		&tsExpiry); // out - lifetime
	if (returncode != SEC_E_OK)
		throw new ssl_exception(format("AcquireCredentialsHandleW failed: 0x%x\n", returncode));

	const DWORD dwSSPIFlags = 
		ISC_REQ_SEQUENCE_DETECT |
		ISC_REQ_REPLAY_DETECT |
		ISC_REQ_CONFIDENTIALITY |
		ISC_RET_EXTENDED_ERROR |
		ISC_REQ_ALLOCATE_MEMORY |
		ISC_REQ_STREAM;
	DWORD dwSSPIOutFlags;

	CtxtHandle hContext;
	CtxtHandle* phContext = &hContext;
	{
		AutoBuffers bufsRequestToken(1, pSecurityFunc);
		bufsRequestToken.SetBufferToken(0, NULL, 0);

		//
		//	requesting a TOKEN
		//
		returncode = pSecurityFunc->InitializeSecurityContextW(
			&hClientCredentials,
			NULL,	// Context Handle is NULL - requesting a TOKEN
			L"minimac.aprelev.com",
			dwSSPIFlags,
			0,
			SECURITY_NATIVE_DREP,
			NULL,
			0,
			phContext,
			&bufsRequestToken,
			&dwSSPIOutFlags,
			&tsExpiry);
		if (returncode != SEC_I_CONTINUE_NEEDED)
			throw new ssl_exception(format("InitializeSecurityContext failed: %d. Expected follow up security context initialization.", returncode));

		if (bufsRequestToken[0].cbBuffer != 0 && bufsRequestToken[0].pvBuffer != NULL)
		{
			DWORD cbData = send(s, (const char*)bufsRequestToken[0].pvBuffer, bufsRequestToken[0].cbBuffer, 0);
			if (cbData == SOCKET_ERROR || cbData == 0)
			{
				pSecurityFunc->DeleteSecurityContext(phContext);
				throw new ssl_exception(format("Failed to send response from InitializeSecurityContext : %d", WSAGetLastError()));
			}
			printf("%d bytes of handshake data sent to server\n", cbData);
		}
	}

	SecBuffer ExtraData;

	//
	// Client handshake loop
	//
	const int IO_BUFFER_SIZE = 0x10000;
	PCHAR iobuffer = (PCHAR)LocalAlloc(LMEM_FIXED, IO_BUFFER_SIZE);
	if (iobuffer == NULL)
		printf("Failed to allocate %d bytes: %d\n", IO_BUFFER_SIZE, GetLastError());
	DWORD cbIOBuffer = 0;

	SECURITY_STATUS sc = SEC_I_CONTINUE_NEEDED;
	while (sc == SEC_I_CONTINUE_NEEDED || sc == SEC_E_INCOMPLETE_MESSAGE || sc == SEC_I_INCOMPLETE_CREDENTIALS)
	{
		if (cbIOBuffer == 0 || sc == SEC_E_INCOMPLETE_MESSAGE)
		{
			DWORD cbData = recv(s, iobuffer + cbIOBuffer, IO_BUFFER_SIZE - cbIOBuffer, 0);
			switch(cbData)
			{
				case SOCKET_ERROR:
					printf("Failed to read from socket %d\n", WSAGetLastError());
					sc = SEC_E_INTERNAL_ERROR;
					break;
				case 0:
					printf("Server disconnected unexpectedly\n");
					sc = SEC_E_INTERNAL_ERROR;
					break;
				default:
					printf("Received %d bytes of handshake data\n", cbData);
					cbIOBuffer += cbData;
			}
		}


		SecBuffer InBuffers[2];
		InBuffers[0].pvBuffer = iobuffer; // used to receive data from the server
		InBuffers[0].cbBuffer = cbIOBuffer;
		InBuffers[0].BufferType = SECBUFFER_TOKEN;
		InBuffers[1].pvBuffer = NULL; // leftovers will be placed in buffer 1 
		InBuffers[1].cbBuffer = 0; // and given a buffer type of SECBUFFER_EXTRA
		InBuffers[1].BufferType = SECBUFFER_EMPTY;
		SecBufferDesc InBuffer;
		InBuffer.cBuffers = 2;
		InBuffer.pBuffers = InBuffers;
		InBuffer.ulVersion = SECBUFFER_VERSION;

		SecBuffer OutBuffers[1];
		OutBuffers[0].pvBuffer = NULL;
		OutBuffers[0].BufferType = SECBUFFER_TOKEN;
		OutBuffers[0].cbBuffer = 0;
		SecBufferDesc OutBuffer;
		OutBuffer.cBuffers = 1;
		OutBuffer.pBuffers = OutBuffers;
		OutBuffer.ulVersion = SECBUFFER_VERSION;

		returncode = pSecurityFunc->InitializeSecurityContextW(
			&hClientCredentials,
			phContext,
			NULL,
			dwSSPIFlags,
			0,
			SECURITY_NATIVE_DREP,
			&InBuffer,
			0,
			NULL,
			&OutBuffer,
			&dwSSPIOutFlags,
			&tsExpiry);

		if (returncode == SEC_E_OK || 
			returncode == SEC_I_CONTINUE_NEEDED || 
			FAILED(returncode) && (dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR))
		{
			if (OutBuffers[0].cbBuffer != 0 && OutBuffers[0].pvBuffer != NULL)
			{
				DWORD cbData = send(s, (char*)(OutBuffers[0].pvBuffer), OutBuffers[0].cbBuffer, 0);
				if (cbData == SOCKET_ERROR || cbData == 0)
				{
					printf("Failed to send data to server: %d\n", WSAGetLastError());
					pSecurityFunc->FreeContextBuffer(OutBuffers[0].pvBuffer);
					pSecurityFunc->DeleteSecurityContext(phContext);
				}
				printf("Sent %d bytes of handshake\n", cbData);
				pSecurityFunc->FreeContextBuffer(OutBuffers[0].pvBuffer);
				OutBuffers[0].pvBuffer = NULL;
			}
		}

		if (returncode == SEC_E_INCOMPLETE_MESSAGE)
			continue;

		if (returncode == SEC_E_OK)
		{
			if (InBuffers[1].BufferType == SECBUFFER_EXTRA)
			{
				//
				//	Stash extra data received for future use
				//
				ExtraData.pvBuffer = LocalAlloc(LMEM_FIXED, InBuffers[1].cbBuffer);
				if (ExtraData.pvBuffer == NULL)
				{
					printf("Failed to allocate %d bytes: %d\n", IO_BUFFER_SIZE, GetLastError());
					throw std::bad_alloc();//new ssl_exception(vformat("Failed to allocate %d bytes: %d\n", IO_BUFFER_SIZE, GetLastError()));
				}
				MoveMemory(ExtraData.pvBuffer, iobuffer + (cbIOBuffer - InBuffers[1].cbBuffer), InBuffers[1].cbBuffer);
				ExtraData.cbBuffer = InBuffers[1].cbBuffer;
				ExtraData.BufferType = SECBUFFER_TOKEN;
				printf("Received extra %d bytes of data with handshake data\n", ExtraData.cbBuffer);
			}
			else
			{
				ExtraData.pvBuffer = NULL;
				ExtraData.cbBuffer = 0;
				ExtraData.BufferType = SECBUFFER_EMPTY;
			}
			break;
		}

		if (FAILED(returncode))
		{
			printf("Second InitializeSecurityContext failed : 0x%x\n", returncode);
			break;
		}

		if (returncode == SEC_I_INCOMPLETE_CREDENTIALS)
		{
			printf("Server didn't like our client certificate. Oh, well.\n");
			break;
		}

		//
		//	reuse "extra" leftovers
		//
		if (InBuffers[1].BufferType == SECBUFFER_EXTRA)
		{
			MoveMemory(iobuffer, iobuffer + (cbIOBuffer - InBuffers[1].cbBuffer), InBuffers[1].cbBuffer);
			cbIOBuffer = InBuffers[1].cbBuffer;
		}
		else
			cbIOBuffer = 0;
	}

	if (FAILED(returncode)) pSecurityFunc->DeleteSecurityContext(phContext);
	LocalFree(iobuffer);

	SecPkgContext_StreamSizes sizes;
	returncode = pSecurityFunc->QueryContextAttributesW(phContext, SECPKG_ATTR_STREAM_SIZES, &sizes);
	if (FAILED(returncode))
		throw new ssl_exception(format("Failed to query context attributes: 0x%h\n", returncode));

	cbIOBuffer = sizes.cbHeader + sizes.cbMaximumMessage + sizes.cbTrailer;
	iobuffer = (char*)LocalAlloc(LMEM_FIXED, cbIOBuffer);
	if (iobuffer == NULL) throw new std::bad_alloc();

	DWORD cposIOBuffer = 0;
	returncode = 0;
	while(1)
	{
		if (cposIOBuffer == 0 || returncode == SEC_E_INCOMPLETE_MESSAGE)
		{
			int recved = recv(s, iobuffer + cposIOBuffer, IO_BUFFER_SIZE - cposIOBuffer, 0);
			switch(recved)
			{
				case SOCKET_ERROR:
					printf("Failed to read from socket %d\n", WSAGetLastError());
					returncode = SEC_E_INTERNAL_ERROR;
					break;
				case 0:
					printf("Server disconnected unexpectedly\n");
					returncode = SEC_E_INTERNAL_ERROR;
					break;
				default:
					printf("Received %d bytes of handshake data\n", recved);
					cposIOBuffer += recved;
			}
		}

		SecBuffer Buffers[4];
		Buffers[0].pvBuffer = iobuffer;
		Buffers[0].cbBuffer = cposIOBuffer;
		Buffers[0].BufferType = SECBUFFER_DATA;
		Buffers[1].BufferType = SECBUFFER_EMPTY;
		Buffers[2].BufferType = SECBUFFER_EMPTY;
		Buffers[3].BufferType = SECBUFFER_EMPTY;
		SecBufferDesc BuffersDesc;
		BuffersDesc.ulVersion = SECBUFFER_VERSION;
		BuffersDesc.cBuffers = 4;
		BuffersDesc.pBuffers = Buffers;
		returncode = pSecurityFunc->DecryptMessage(phContext, &BuffersDesc, 0, NULL);
		if (returncode == SEC_I_CONTEXT_EXPIRED)
			break; // end of session
		if (returncode != SEC_E_OK && returncode != SEC_I_RENEGOTIATE && returncode != SEC_I_CONTEXT_EXPIRED)
			throw new ssl_exception(format("Failed to decrypt message: 0x%h\n", returncode));

		SecBuffer *pDataBuffer = NULL, *pExtraBuffer = NULL;
		for (int i = 1; i < 4; i++)
		{
			if (pDataBuffer == NULL && Buffers[i].BufferType == SECBUFFER_DATA)
				pDataBuffer = &Buffers[i];
			if (pExtraBuffer == NULL && Buffers[i].BufferType == SECBUFFER_EXTRA)
				pExtraBuffer = &Buffers[i];
		}

		if (pDataBuffer)
		{
			int length = pDataBuffer->cbBuffer;
			if (length > 2)
				if (((char*)pDataBuffer->pvBuffer)[length-2] == 13 && ((char*)pDataBuffer->pvBuffer)[length-1] == 10) break;
		}

		if (pExtraBuffer)
		{
			MoveMemory(&iobuffer, pExtraBuffer->pvBuffer, pExtraBuffer->cbBuffer);
			cposIOBuffer = pExtraBuffer->cbBuffer;
		}
		else
			cposIOBuffer = 0;

		if (returncode == SEC_I_RENEGOTIATE)
			throw new ssl_exception("Server is too picky, wants to renegotiate. Forget it\n");
	}

	sprintf(iobuffer + sizes.cbHeader, "%s", "EHLO \r\n");

	{
		Buffers bMessage(4);
		bMessage.SetBufferStreamHeader(0, iobuffer, sizes.cbHeader);
		bMessage.SetBufferData(1, iobuffer + sizes.cbHeader, strlen(iobuffer + sizes.cbHeader));
		bMessage.SetBufferStreamTrailer(2, iobuffer + sizes.cbHeader + strlen(iobuffer + sizes.cbHeader), sizes.cbTrailer);
		bMessage.SetBufferEmpty(3);

		returncode = pSecurityFunc->EncryptMessage(phContext, 0, &bMessage, 0);
		if (FAILED(returncode))
			throw new ssl_exception(format("Failed to encrypt message: 0x%h\n", returncode));

		int cbData = send(s, iobuffer, bMessage.totalLength()/*OutBuffers[0].cbBuffer + OutBuffers[1].cbBuffer + OutBuffers[2].cbBuffer*/, 0);
	}
	LocalFree(iobuffer);
	//
	// read a response
	//



	closesocket(s);
	WSACleanup();


	//PCCERT_CONTEXT pCertContext = getServerCertificate();


	//SCHANNEL_CRED* m_pSChannelCred = new SCHANNEL_CRED();

	//m_pSChannelCred->dwVersion  = SCHANNEL_CRED_VERSION;
	//if(pCertContext != NULL)
	//{
	//	m_pSChannelCred->cCreds     = 1;
	//	m_pSChannelCred->paCred     = &pCertContext;
	//}
	//m_pSChannelCred->grbitEnabledProtocols = SP_PROT_NONE;
	//m_pSChannelCred->dwFlags |= SCH_CRED_NO_DEFAULT_CREDS|SCH_CRED_MANUAL_CRED_VALIDATION;

	//CredHandle* phClientCreds = new CredHandle();
	//TimeStamp tsExpiry;

	//SECURITY_STATUS Status = pSecurityFunc->AcquireCredentialsHandle(
	//	NULL,                   // Name of principal    
	//	UNISP_NAME_W,           // Name of package
	//	SECPKG_CRED_OUTBOUND,   // Flags indicating use
	//	NULL,                   // Pointer to logon ID
	//	m_pSChannelCred,        // Package specific data
	//	NULL,                   // Pointer to GetKey() func
	//	NULL,                   // Value to pass to GetKey()
	//	phClientCreds,        // (out) Cred Handle
	//	&tsExpiry);             // (out) Lifetime (optional)        




	//DWORD           dwSSPIFlags;
	//DWORD           dwSSPIOutFlags;
	//SECURITY_STATUS scRet = S_OK;

	//dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT   |
	//	ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR  |
	//	ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM;

	//CtxtHandle* phContext = NULL;
	//PSecBufferDesc OutBuffer = NULL;
	//scRet = pSecurityFunc->InitializeSecurityContextW(
	//	phClientCreds,	// pchCredentials
	//	NULL,			// pchContext
	//	L"minimac",		// pszTargetName
	//	dwSSPIFlags,	// fContextReq
	//	0,				// Reserved
	//	SECURITY_NATIVE_DREP, // TargetDataRep
	//	NULL,			// pInput
	//	0,				// Reserved
	//	phContext,		// pchNewContext
	//	OutBuffer,		// pOutput
	//	&dwSSPIOutFlags,// pfContextAttr
	//	&tsExpiry);		// ptsExpiry

	//closesocket(s);
	//WSACleanup();

	//SSL_load_error_strings();
	//SSL_library_init();

	//SSL_CTX* ctx = SSL_CTX_new(SSLv3_method());

	//SSL* ssl = SSL_new(ctx);
	//int ret = SSL_connect(ssl);
	//if (ret != 1)
	//	processError(ssl, ret);	
	//return 0;
}

